9.3.1 通过通道实现同步

也许你已经猜到了,通道非常适用于对两个goroutine进行同步,当一个goroutine需要依赖另一个goroutine时,更是如此。事不宜迟,让我们马上来看看代码清单9-7所示的程序:这个程序沿用了上一节展示过的例子,唯一的不同在于,这次的程序使用了通道而不是等待组来对goroutine进行同步。

代码清单9-7 使用通道同步goroutine

package main
import "fmt"
import "time"
func printNumbers2(w chan bool) {
 for i := 0; i < 10; i++ {
  time.Sleep(1 * time.Microsecond)
  fmt.Printf("%d ", i)
 }
 w <- true}func printLetters2(w chan bool) { ❶
 for i := 'A'; i < 'A'+10; i++ { ❶
  time.Sleep(1 * time.Microsecond) ❶
  fmt.Printf("%c ", i) ❶
 } ❶
 w <- true}
func main() {
 w1, w2 := make(chan bool), make(chan bool)
 go printNumbers2(w1)
 go printLetters2(w2)
 <-w1 ❷
 <-w2 ❷
}

❶ 把一个布尔值放入通道,以便解除主程序的阻塞状态

❷ 主程序将一直阻塞,直到通道里面出现可弹出的值为止

先来看看这个程序中的 main 函数。它首先创建了 w1w2 这两个 bool 类型的通道,接着以goroutine方式运行了 printNumbers2 函数和 printLetters2 函数,并将两个通道分别传给了这两个函数。在启动两个goroutine之后, main 函数将会尝试从通道 w1 中移除一个值,但由于通道 w1 当时并没有包含任何值,所以 main 函数将会在此处阻塞。当 printNumbers2 即将执行完毕,并将一个 true 值放入通道 w1 之后, main 函数的阻塞状态才会被解除,并继续尝试从第二个通道 w2 中弹出一个值。跟之前一样,在 printLetters2 执行完毕并将 true 值放入通道 w2 之前, main 函数将一直阻塞,直到它成功取得了 w2 通道中的 true 值之后,阻塞才会解除,然后 main 函数才会顺利退出。

需要注意的是,因为我们只是想要在goroutine执行完毕之后解除对 main 函数的阻塞,而不是真正地想要使用通道中存储的值,所以程序在从通道 w1w2 里面取出值之后并没有使用这些值。

代码清单9-7展示的是一个非常简单的例子,这个例子中的程序使用通道只是为了对多个goroutine进行同步,但这些goroutine之间并没有通信。不过在接下来的一节,我们就会看到一个在多个goroutine之间传递消息的例子。

results matching ""

    No results matching ""